Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[shared_preferences] update List<String> encode/decode #8335

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

tarrinneal
Copy link
Contributor

@tarrinneal tarrinneal commented Dec 20, 2024

Follow up to #8187

Updates Android List<String> encoding/decoding to use JSON to avoid potential future breakages from restricted list types.

@tarrinneal tarrinneal marked this pull request as ready for review January 3, 2025 12:25
@tarrinneal tarrinneal requested a review from reidbaker as a code owner January 3, 2025 12:25
@tarrinneal
Copy link
Contributor Author

@stuartmorgan ready for review here as well

private @NonNull Map<String, Object> getAllPrefs(
@NonNull String prefix, @Nullable Set<String> allowList) throws RuntimeException {
Map<String, ?> allPrefs = preferences.getAll();
Map<String, Object> filteredPrefs = new HashMap<>();
for (String key : allPrefs.keySet()) {
if (key.startsWith(prefix) && (allowList == null || allowList.contains(key))) {
filteredPrefs.put(key, transformPref(key, allPrefs.get(key)));
filteredPrefs.put(key, transformPref(key, Objects.requireNonNull(allPrefs.get(key))));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was requireNonNull needed here? Also this code is getting a bit difficult to parse. (A loop with a conditional that sets some transformed filtered data) Consider breaking parts out into methods or adding comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a change suggested by a warning I was getting in Android Studio. Since the method being called requires nonnull arguments and getting a value from a map doesn't programmatically guarantee a value. In this context, there would always be a value though.

@@ -148,32 +141,14 @@ public void onDetachedFromEngine(@NonNull FlutterPlugin.FlutterPluginBinding bin
private Object transformPref(@NonNull String key, @NonNull Object value) {
if (value instanceof String) {
String stringValue = (String) value;
if (stringValue.startsWith(LIST_IDENTIFIER)) {
if (stringValue.startsWith(JSON_LIST_IDENTIFIER)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is where having the keys be similar starts to be important. That said from reading the code the reader does not know the keys are overlapping and it would seem safe in code review to swap the order of these if statements.

Consider making the keys independent so that you are not relying on the contents of the keys. If that is too much code change then consider making a "LIST_PREFIX" that can be checked so that it is at least clear in code what the relationship is.

If you want further reading see
https://www.16elt.com/2024/09/25/first-book-of-byte-sized-tech/

I think the first example explains the principal I am applying.

Copy link
Contributor

@stuartmorgan stuartmorgan Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making the keys independent so that you are not relying on the contents of the keys.

This is something Tarrin and I had discussed offline; making it a prefix avoids this being a potentially (very unlikely, but still possible) breaking change, by using our already-reserved space.

I would strongly prefer we keep that, and adjust the code to make it explicit to readers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I can understand that fear and why it might fail. Thank you for being open to structuring the code differently so that the overlap is easier to follow for future maintainers.

@@ -1,3 +1,9 @@
## 3.0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the breaking changes required? if not consider fixing/mitigating the security issue independent of the breaking changes. It makes it more likely for them to be adopted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking changes to shared_preferences have the potential to be quite disruptive to the ecosystem; I would strongly prefer we keep the legacy type support around to making a breaking change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I originally expected this change was going to end up being "technically" breaking due to the new prefix (before we discussed the prefix extension plan) so I wanted to wrap these long awaited breaking changes in as well. I'll revert them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking changes to shared_preferences have the potential to be quite disruptive to the ecosystem; I would strongly prefer we keep the legacy type support around to making a breaking change.

Should I revert the error handling changes as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I revert the error handling changes as well?

I did this.

@@ -39,20 +41,27 @@ class SharedPreferencesAndroid extends SharedPreferencesStorePlatform {
Future<bool> setValue(String valueType, String key, Object value) async {
switch (valueType) {
case 'String':
return _api.setString(key, value as String);
value as String;
if (value.startsWith(listPrefix) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this list grow? if so consider making a set of prefixes to check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't generally add types to shared_preferences since anything that all platforms don't support ends up with unpleasant complexity like the List<String> mess we are currently dealing with.

@@ -1,3 +1,9 @@
## 3.0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking changes to shared_preferences have the potential to be quite disruptive to the ecosystem; I would strongly prefer we keep the legacy type support around to making a breaking change.

@@ -39,20 +41,27 @@ class SharedPreferencesAndroid extends SharedPreferencesStorePlatform {
Future<bool> setValue(String valueType, String key, Object value) async {
switch (valueType) {
case 'String':
return _api.setString(key, value as String);
value as String;
if (value.startsWith(listPrefix) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't generally add types to shared_preferences since anything that all platforms don't support ends up with unpleasant complexity like the List<String> mess we are currently dealing with.

@tarrinneal tarrinneal changed the title [shared_preferences] update List<String> encode/decode and other simple breaking changes [shared_preferences] update List<String> encode/decode Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants